﻿using NLog;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tools.Client.Library.Dictionary;

namespace Tools.Client.Library.Connection
{
    class RabbitMQ
    {
        private static readonly Lazy<RabbitMQ> lazy =
           new Lazy<RabbitMQ>(() => new RabbitMQ());
        public static RabbitMQ Instance { get { return lazy.Value; } }
        private RabbitMQ(){}

        protected IConnection _IConnection = null;

        protected IModel _ProductIModel = null;

        protected IModel _ConsumeIModel = null;

        public void Product(QueueConfig config, string message)
        {
            if (_IConnection == null)
            {
                throw new Exception("MQ未连接！");
            }
            if (_ProductIModel == null || _ProductIModel.IsClosed)
            {
                _ProductIModel = _IConnection.CreateModel();

                _ProductIModel.ExchangeDeclare(config.ExchangeName, config.ExchangeType, true);
                _ProductIModel.QueueDeclare(config.QueueName, config.Durable, false, config.AutoDelete, null);
                _ProductIModel.QueueBind(config.QueueName, config.ExchangeName, config.RoutingKey);                
            }

            IBasicProperties properties = _ProductIModel.CreateBasicProperties();
            byte[] body = Encoding.UTF8.GetBytes(message);
            _ProductIModel.BasicPublish(config.ExchangeName, config.QueueName, properties, body);

        }

        public void Consume(QueueConfig config, Action<string> callback, Action<string> errorCallback)
        {
            if(_IConnection == null)
            {
                throw new Exception("MQ未连接！");
            }
            if (_ConsumeIModel == null || _ConsumeIModel.IsClosed)
            {
                _ConsumeIModel = _IConnection.CreateModel();

                _ConsumeIModel.ExchangeDeclare(config.ExchangeName, config.ExchangeType, true);
                _ConsumeIModel.QueueDeclare(config.QueueName, config.Durable, false, config.AutoDelete, null);
                _ConsumeIModel.QueueBind(config.QueueName, config.ExchangeName, config.RoutingKey);
                _ConsumeIModel.BasicQos(0, 2, false);

                EventingBasicConsumer consumer = new EventingBasicConsumer(_ConsumeIModel);                

                consumer.Received += (sender, e) =>
                {
                    var body = e.Body.ToArray();
                    string message = Encoding.UTF8.GetString(body);
                    try
                    {
                        callback(message);
                        _ConsumeIModel.BasicAck(e.DeliveryTag, false);
                    }
                    catch(Exception ex)
                    {
                        errorCallback(ex.Message);
                    }
                };

                _ConsumeIModel.BasicConsume(config.QueueName, false, consumer);
            }
        }

        public void Connection(MQConfig config)
        {
            try
            {
                ConnectionFactory _ConnectionFactory  = new ConnectionFactory()
                {
                    HostName = config.HostName,
                    UserName = config.UserName,
                    Password = config.Password,
                    Port = config.Port,
                    VirtualHost = config.VirtualHost,
                    AutomaticRecoveryEnabled = true                 
                };

                _IConnection = _ConnectionFactory.CreateConnection("luffy.tools.mq");
            }
            catch(Exception ex)
            {
                LogManager.GetCurrentClassLogger().Warn(ex.Message);
                throw new Exception("RabbitMQ连接失败，请检查你的参数。");
            }
        }

        public void ReConnection(MQConfig config)
        {
            this.Close();
            this.Connection(config);
        }
        public void Close()
        {
            if (_ProductIModel != null && _ProductIModel.IsOpen)
            {
                _ProductIModel.Close();
            }
            if (_ConsumeIModel != null && _ConsumeIModel.IsOpen)
            {
                _ConsumeIModel.Close();
            }
            if (_IConnection != null && _IConnection.IsOpen)
            {
                _IConnection.Close();
            }
        }
        public bool IsOpen()
        {
            if(_IConnection != null)
            {
                return _IConnection.IsOpen;
            }
            return false;
        } 
        
        public bool ConsumeIModelOpen()
        {
            if(_ConsumeIModel != null)
            {
                return _ConsumeIModel.IsOpen;
            }
            return false;
        }
    }    
}
